package tv.athena.live.base.manager

import android.arch.lifecycle.Lifecycle
import android.arch.lifecycle.LifecycleObserver
import android.arch.lifecycle.OnLifecycleEvent
import android.arch.lifecycle.ProcessLifecycleOwner
import com.yy.liveplatform.proto.nano.LpfLiveroomtemplateV2
import tv.athena.annotation.MessageBinding
import tv.athena.core.axis.Axis
import tv.athena.core.sly.Sly
import tv.athena.live.api.IDataCallback
import tv.athena.live.api.channel.IChannelService
import tv.athena.live.base.LiveRoomBzMode
import tv.athena.live.basesdk.config.BaseDataConfig
import tv.athena.live.basesdk.thunderblotwrapper.AbscThunderEventListener
import tv.athena.live.basesdk.thunderblotwrapper.ThunderHandleManager
import tv.athena.live.channel.ChannelRepositiy
import tv.athena.live.channel.ChannelServiceSDKImpl
import tv.athena.live.channel.RoomStatusEvent
import tv.athena.live.utils.ALog
import tv.athena.live.utils.RoomInfoV2Repository
import tv.athena.live.utils.ServiceUtils
import tv.athena.service.api.MessageResponse
import tv.athena.service.api.ServiceFailResult

/**
 *    create by chenhaofeng 2019-11-15
 *
 *
 */
class LiveRoomComponentManager : ComponentManager(), LifecycleObserver {
    private val TAG = "LiveRoomComponentManager"
    private var mIChannelService: IChannelService? = null
    private var hasCreateComponent = false

    //@Deprecated("请使用string类型的sid", ReplaceWith("initComponent(sid: String?, ...)"))
    fun initComponent(
            myUid: Long?,
            config: ComponentConfig,
            liveRoomBzMode: LiveRoomBzMode = LiveRoomBzMode.NORMAL) {
        initComponent(sid = 0L, myUid = myUid, componentConfigs = config.components, liveRoomBzMode = liveRoomBzMode)
    }

    //@Deprecated("请使用string类型的sid", ReplaceWith("initComponent(sid: String?, ...)"))
    fun initComponent(sid: Long?,
                      myUid: Long?,
                      componentConfigs: List<String>,
                      liveRoomBzMode: LiveRoomBzMode = LiveRoomBzMode.NORMAL) {
        initComponent(sid.toString(), myUid, componentConfigs, liveRoomBzMode)
    }

    /**
     * 初始化 LiveRoomComponent 的各个模块，选择模块可以通过
     * @see ComponentConfig
     * @param sid 房间 可不填
     * @param myUid 登录用户的uid
     * @param liveRoomBzMode
     * @see LiveRoomBzMode
     */
    fun initComponent(sid: String? = null,
                      myUid: Long?,
                      componentConfigs: List<String>,
                      liveRoomBzMode: LiveRoomBzMode = LiveRoomBzMode.NORMAL) {
        ALog.i(TAG, "initComponent( $sid, $myUid, $componentConfigs, $liveRoomBzMode)")

        /**
         * TODO 两个疑留问题
         * 1、当前还没有协同前后端把sid统一改为String类型，但又有一些业务要用到String类型的sid，但又需要在此初始化sid，故临时这样实现
         * 2、mCommonViewModel.setSid会在joinRoom成功后统一赋值，但这个时机其实晚了，比如在joinRoom前调用接受连麦接口，就会因为sid
         * 为空把流程中断
         */
        if (!sid.isNullOrEmpty()) {
            sid.toLongOrNull()?.let {
                mCommonViewModel.setSid(it)
            }
        }
        myUid?.let {
            mCommonViewModel.setMyUid(it)
        }

        mComponentContext.mLiveRoomBzMode = liveRoomBzMode
        initChannelService(liveRoomBzMode)
        mComponentContext.componentManager = this
        mComponentContext.commonViewModel = mCommonViewModel
        val componentConfigBuilder = ComponentConfigBuilder()
        for (comName in componentConfigs) {
            componentConfigBuilder.addComponent(comName)
        }
        val componentInfos = componentConfigBuilder.build()
        traverseToInit(componentInfos)
        onAllReady()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
        createAllComponent()

        //监听加入频道成功的通知，用来更新mCommonViewModel.sid
        mComponentContext.thunderHandle?.registerThunderEventListener(thunderEventListener)
    }

    private fun initChannelService(liveRoomBzMode: LiveRoomBzMode) {
        mIChannelService = when (liveRoomBzMode) {
            LiveRoomBzMode.PURESDK -> ChannelServiceSDKImpl()
            LiveRoomBzMode.NORMAL -> Axis.getService(IChannelService::class.java)
        }
    }

    fun joinRoom(uid: Long,
                 userName: String? = uid.toString(),
                 sid: Long,
                 password: String? = "",
                 token: String? = "",
                 positionToken: String? = "",
                 extend: String? = "",
                 callback: IDataCallback<IChannelService.EnterChannelResult>? = null) {
        mCommonViewModel.sid = sid
        ALog.i(TAG, "joinRoom $this")
        Sly.subscribe(this)
        activatingThunderHandle()
        BaseDataConfig.getAudienceStreamConfigReq()
        mIChannelService?.entranceChannel(uid, userName, sid, password, token, positionToken, extend, callback)
        createAllComponent()
    }

    fun joinRoom(uid: Long,
                 userName: String? = uid.toString(),
                 sid: String,
                 password: String? = "",
                 token: String? = "",
                 positionToken: String? = "",
                 extend: String? = "",
                 callback: IDataCallback<IChannelService.EnterChannelResult>? = null) {
        ALog.i(TAG, "joinRoom $this")
        Sly.subscribe(this)
        activatingThunderHandle()
        //每次加入都要请求一下cdn策略
        BaseDataConfig.getAudienceStreamConfigReq()
        mIChannelService?.entranceChannel(uid, userName, sid, password, token, positionToken, extend, callback)
        createAllComponent()
    }

    fun leaveRoom(uid: Long, sid: Long, extend: String = "") {
        ALog.i(TAG, "leaveRoom uid:$uid, sid:$sid")
        mIChannelService?.leaveChannel(uid, sid, extend)
        deInitComponent()
    }

    fun leaveRoom(uid: Long, sid: String) {
        ALog.i(TAG, "leaveRoom uid:$uid, sid:$sid")
        mIChannelService?.leaveChannel(uid, sid)
        deInitComponent()
    }

    fun activatingThunderHandle() {
        ALog.i(TAG, "activatingThunderHandle()  $this")
        ThunderHandleManager.activatingThunderHandle(this)
    }

    @MessageBinding
    fun onRoomStatusEvent(event: RoomStatusEvent) {
        if (event.status == 0) {
            Sly.unSubscribe(this)
            ALog.i(TAG, "onRoomStatusEvent roomId ${event.streamRoomId}")
            mCommonViewModel.streamRoomId = event.streamRoomId
        }
    }

    fun deInitComponent() {
        mComponentContext?.thunderHandle?.unRegisterAllRtcEventListener()
        destroyAllComponent()
        Sly.unSubscribe(this)
        ProcessLifecycleOwner.get().lifecycle.removeObserver(this)
    }

    /**
     * 通过该接口可以实现 如果业务有自身的 频道号（StreamRoomId）需要通过该接口来进行
     * 转换成 中台对应的 sid ,用于进行广播接收。该接口需要保证成功，不成功收不到
     * 中台广播, 目前中台的房间内的广播需要依赖这个
     */
    fun registerBroadcastByStreamRoomId(streamRoomId: String,
                                        callback: IDataCallback<LpfLiveroomtemplateV2.GetLiveRoomInfoRespV2>?) {
        val req = LpfLiveroomtemplateV2.GetLiveRoomInfoReqV2()
        req.bzSid = streamRoomId
        RoomInfoV2Repository.getLiveRoomInfoRespV2(req, object :
                ServiceUtils.SvcResultCusRetryCallBack<LpfLiveroomtemplateV2.GetLiveRoomInfoRespV2>() {
            override fun get(): LpfLiveroomtemplateV2.GetLiveRoomInfoRespV2 {
                return LpfLiveroomtemplateV2.GetLiveRoomInfoRespV2()
            }

            override fun onMessageFail(errorCode: ServiceFailResult, ex: Exception?) {
                ALog.i(TAG, "registerChannelBroadcast onMessageFail($errorCode)")
                callback?.onDataNotAvailable(errorCode = errorCode.getResultCode(), desc = errorCode.description)
            }

            override fun onMessageSuccess(response: MessageResponse<LpfLiveroomtemplateV2.GetLiveRoomInfoRespV2>) {
                ALog.i(TAG, "registerChannelBroadcast onMessageSuccess ${response.message.code}")
                when (response.message.code) {
                    0 -> {
                        response.message.liveRoomInfo?.channelInfo?.sid?.let {
                            ChannelRepositiy.registerChannelBroadcast(it, object : IDataCallback<Int> {
                                override fun onDataLoaded(result: Int) {
                                    callback?.onDataLoaded(response.message)
                                }

                                override fun onDataNotAvailable(errorCode: Int, desc: String) {
                                    ALog.i(TAG, "registerChannelBroadcast onServiceFailed code = $errorCode, " +
                                            "desc = $desc")
                                    callback?.onDataNotAvailable(errorCode, desc)
                                }
                            })
                        }
                    }
                    else -> {
                        ALog.i(TAG, "registerChannelBroadcast onFailed code = ${response.message.code}")
                        callback?.onDataNotAvailable(response.message.code, response.message.message)
                    }
                }
            }
        })
    }

    /**
     * 所有的Component 统一调用 onDestroy() 方法
     */
    private fun destroyAllComponent() {
        for (key in mComponents.keys) {
            val component = mComponents[key]
            component?.onDestroy()
        }
        hasCreateComponent = false
    }

    private fun createAllComponent() {
        if (hasCreateComponent) {
            return
        }
        for (key in mComponents.keys) {
            val component = mComponents[key]
            component?.onCreate()
        }
        hasCreateComponent = true
    }

    /**
     *  应用 在前台
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun appOnForeground() {
        //todo
    }

    /**
     * 应用 退到后台
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun appOnBackground() {
        //todo
    }

    /**
     * 仅作临时获取成功加入频道的通知
     *
     * 因为如果业务端使用LiveRoomComponentManager来初始化，并且使用IChannelService来加入频道，
     * mComponentContext.commonViewModel.sid将得不到更新
     */
    private val thunderEventListener = object : AbscThunderEventListener() {
        override fun onJoinRoomSuccess(room: String?, uid: String?, elapsed: Int) {
            val sidLong = room?.toLong()
            val uidLong = uid?.toLong()
            ALog.i(TAG, "***** onJoinRoomSuccess sid:$sidLong uid:$uid elapsed:$elapsed *****")
            sidLong?.let {
                mComponentContext?.commonViewModel?.sid = sidLong
            }
            uidLong?.let {
                mComponentContext?.commonViewModel?.myUid = uidLong
            }
        }
    }

    /**
     * 因为mIChannelService是单例，尚未改造为component。后面把ChannelService的hasJoinAthRoom变量整合到commonViewModel中
     */
    fun hasJoinAthRoom(): Boolean {
        return mIChannelService?.hasJoinAthRoom() ?: false || commonViewModel?.hasJoinAthRoom() ?: false
    }

    fun hasJoinRoom(): Boolean {
        return hasJoinAthRoom() && ThunderHandleManager.hasJoinRoom
    }

    fun hasJoinMediaRoom(): Boolean {
        return ThunderHandleManager.hasJoinRoom
    }
}